package cs4383;

import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;

import javax.media.j3d.Background;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.Locale;
import javax.media.j3d.Node;
import javax.media.j3d.PhysicalBody;
import javax.media.j3d.PhysicalEnvironment;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.View;
import javax.media.j3d.ViewPlatform;
import javax.media.j3d.VirtualUniverse;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.vecmath.Point2d;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;

import jp.nyatla.nyartoolkit.core.NyARCode;
import jp.nyatla.nyartoolkit.java3d.utils.J3dNyARParam;
import jp.nyatla.nyartoolkit.java3d.utils.NyARSingleMarkerBehaviorHolder;
import jp.nyatla.nyartoolkit.java3d.utils.NyARSingleMarkerBehaviorListener;

import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.SimpleUniverse;

/**
 * Java3Dサンプルプログラム 単一マーカー追跡用のBehaviorを使って、背景と１個のマーカーに連動した TransformGroupを動かします。
 * 
 */
public class TEST_NyARJava3D extends JFrame implements
		NyARSingleMarkerBehaviorListener {
	private static final long serialVersionUID = -8472866262481865377L;

	private final String CARCODE_FILE = "patt.hiro";

	private final String CARCODE_FILE_2 = "patt.kanji";

	private final String PARAM_FILE = "camera_para.dat";

	// NyARToolkit関係
	private NyARSingleMarkerBehaviorHolder nya_behavior;

	private J3dNyARParam ar_param;

	// universe関係
	private Canvas3D canvas;

	private Locale locale;

	private VirtualUniverse universe;

	private List<Furniture> furnitures = new ArrayList<Furniture>();
	private final Action action = new SwingAction();
	private final Action action_1 = new SwingAction_1();

	public static void main(String[] args) {
		try {
			TEST_NyARJava3D frame = new TEST_NyARJava3D();

			frame.setVisible(true);
			Insets ins = frame.getInsets();
			frame.setSize(640 + ins.left + ins.right, 480 + ins.top
					+ ins.bottom);
			frame.setLocationRelativeTo(null);
			frame.startCapture();
			frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void loadObjects() {
		// TODO
	}

	public void onUpdate(boolean i_is_marker_exist, Transform3D i_transform3d) {
		/*
		 * TODO:Please write your behavior operation code here.
		 * マーカーの姿勢を元に他の３Dオブジェクトを操作するときは、ここに処理を書きます。
		 */
	}

	public void startCapture() throws Exception {
		nya_behavior.start();
	}

	private void setup3DCanvas() throws Exception {
		// NyARToolkitの準備
		NyARCode ar_code = new NyARCode(16, 16);
		ar_code.loadARPattFromFile(CARCODE_FILE);
		NyARCode ar_code2 = new NyARCode(16, 16);
		ar_code2.loadARPattFromFile(CARCODE_FILE_2);
		ar_param = new J3dNyARParam();
		ar_param.loadARParamFromFile(PARAM_FILE);
		ar_param.changeScreenSize(320, 240);

		// localeの作成とlocateとviewの設定
		universe = new VirtualUniverse();
		locale = new Locale(universe);
		canvas = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
		canvas.setSize(0, 0);
		View view = new View();
		ViewPlatform viewPlatform = new ViewPlatform();
		view.attachViewPlatform(viewPlatform);
		view.addCanvas3D(canvas);
		view.setPhysicalBody(new PhysicalBody());
		view.setPhysicalEnvironment(new PhysicalEnvironment());

		// 視界の設定(カメラ設定から取得)
		Transform3D camera_3d = ar_param.getCameraTransform();
		view.setCompatibilityModeEnable(true);
		view.setProjectionPolicy(View.PERSPECTIVE_PROJECTION);
		view.setLeftProjection(camera_3d);

		// 視点設定(0,0,0から、Y軸を180度回転してZ+方向を向くようにする。)
		TransformGroup viewGroup = new TransformGroup();
		Transform3D viewTransform = new Transform3D();
		viewTransform.rotY(Math.PI);
		viewTransform.setTranslation(new Vector3d(0.0, 0.0, 0.0));
		viewGroup.setTransform(viewTransform);
		viewGroup.addChild(viewPlatform);
		BranchGroup viewRoot = new BranchGroup();
		viewRoot.addChild(viewGroup);
		locale.addBranchGraph(viewRoot);

		// バックグラウンドの作成
		Background background = new Background();
		BoundingSphere bounds = new BoundingSphere();
		bounds.setRadius(10.0);
		background.setApplicationBounds(bounds);
		background.setImageScaleMode(Background.SCALE_FIT_ALL);
		background.setCapability(Background.ALLOW_IMAGE_WRITE);
		BranchGroup root = new BranchGroup();
		root.addChild(background);

		// TransformGroupで囲ったシーングラフの作成
		TransformGroup transform = new TransformGroup();
		transform.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		transform.addChild(createSceneGraph());
		root.addChild(transform);

		// NyARToolkitのBehaviorを作る。(マーカーサイズはメートルで指定すること)
		nya_behavior = new NyARSingleMarkerBehaviorHolder(ar_param, 30f,
				ar_code, 0.08);
		// Behaviorに連動するグループをセット
		nya_behavior.setTransformGroup(transform);
		nya_behavior.setBackGround(background);

		// 出来たbehaviorをセット
		root.addChild(nya_behavior.getBehavior());
		nya_behavior.setUpdateListener(this);

		// 表示ブランチをLocateにセット
		locale.addBranchGraph(root);
	}

	public TEST_NyARJava3D() throws Exception {
		super("Java3D Example NyARToolkit");
		getContentPane().setLayout(null);

		setup3DCanvas();
		canvas.setBounds(10, 10, 320, 240);
		getContentPane().add(canvas);

		canvas.addKeyListener(new KeyAdapter() {
			@Override
			public void keyTyped(KeyEvent ke) {
				int kc = ke.getKeyChar();
				switch (kc) {
				case 'a':
					rotateLeft();
					break;
				case 'd':
					rotateRight();
					break;
				case 'w':
					scaleUp();
					break;
				case 's':
					scaleDown();
					break;
				case 't':
					px+=0.01;
					TEST_NyARJava3D.this.transformObject();
					break;
				case 'g':
					px-=0.01;
					TEST_NyARJava3D.this.transformObject();
					break;
				case 'f':
					py+=0.01;
					TEST_NyARJava3D.this.transformObject();
					break;
				case 'h':
					py-=0.01;
					TEST_NyARJava3D.this.transformObject();
					break;
				}
			}
		});

		JButton btnLeft = new JButton("LEFT");
		btnLeft.setAction(action);
		btnLeft.setBounds(30, 256, 140, 23);
		getContentPane().add(btnLeft);

		JButton btnRight = new JButton("RIGHT");
		btnRight.setAction(action_1);
		btnRight.setBounds(214, 256, 131, 23);
		getContentPane().add(btnRight);

		// ウインドウの設定
		// setLayout(new BorderLayout());
		// add(canvas, BorderLayout.CENTER);
	}

	TransformGroup tg = new TransformGroup();
	Transform3D mt = new Transform3D();

	/**
	 * シーングラフを作って、そのノードを返す。 このノードは40mmの色つき立方体を表示するシーン。ｚ軸を基準に20mm上に浮かせてる。
	 * 
	 * @return
	 */
	private Node createSceneGraph() {
		mt.setTranslation(new Vector3d(0.00, 0.0, 20 * 0.001));
		// 大きさ 40mmの色付き立方体を、Z軸上で20mm動かして配置）
		tg.setTransform(mt);
		tg.addChild(new ColorCube(20 * 0.001));
		tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		return tg;
	}

	double angle = 0;

	private class SwingAction extends AbstractAction {
		public SwingAction() {
			putValue(NAME, "Rotate Left");
			putValue(SHORT_DESCRIPTION, "Some short description");
		}

		public void actionPerformed(ActionEvent e) {
			rotateLeft();
		}
	}

	private class SwingAction_1 extends AbstractAction {
		public SwingAction_1() {
			putValue(NAME, "Rotate Right");
			putValue(SHORT_DESCRIPTION, "Some short description");
		}

		public void actionPerformed(ActionEvent e) {
			rotateRight();
		}
	}

	double scale = 0;

	public void scaleUp() {
		scale += 0.1;
		transformObject();
	}

	public void scaleDown() {
		scale -= 0.1;
		transformObject();
	}

	Vector3d v = new Vector3d(0.00, 0.0, 20 * 0.001);
	double px = 0;
	double py = 0;
	public void transformObject(){
		mt.rotZ(angle);
		mt.setScale(scale+1);
		System.out.println(String.format("px: %f, py: %f, angle: %f, scale: %f", px,py,angle, scale));
		v.set(px, py, 20*(0.001 + (scale * 0.001)));
		mt.setTranslation(v);
		tg.setTransform(mt);
		Vector3f location= new Vector3f();
		Transform3D t3d = new Transform3D();
		tg.getLocalToVworld(t3d);
		t3d.get(location);
		System.out.println(location);
		
//		Point3d pointIn3dWorld = new Point3d();
//		pointIn3dWorld.set(location.x, location.y, location.z);
//		Point2d screenCoordinates = new Point2d();
//		Transform3D transform = new Transform3D();
//		canvas.getImagePlateToVworld(transform);
//		transform.invert();
////		transform.transform(location);
//		transform.transform(pointIn3dWorld);
//		canvas.getPixelLocationFromImagePlate(pointIn3dWorld, screenCoordinates);
//		System.out.println(screenCoordinates);
	}
	
	public void rotateLeft() {
		angle -= 0.1;
		transformObject();
	}

	public void rotateRight() {
		angle += 0.1;
		transformObject();
	}
}
